/*
 * $Id: dll.c,v 1.8 2005-12-05 15:11:29 bacon Exp $
 */

#include <xp/bas/dll.h>
#include <xp/bas/memory.h>
#include <xp/bas/sysapi.h>
#include <xp/bas/locale.h>
#include <xp/bas/assert.h>

#if defined(_WIN32)
/* include nothing */
#elif defined(__APPLE__) || defined(__MACOSX__)
#include <mach-o/dyld.h>
#else
#include <dlfcn.h>
#endif

xp_dll_t* xp_dll_open (xp_dll_t* dll, const xp_char_t* path)
{
	void* handle;
#if defined(__APPLE__) || defined(__MACOSX__)
	NSObjectFileImage image;
#endif
#ifndef _WIN32
	#ifdef XP_CHAR_IS_MCHAR
	const xp_mchar_t* mpath = path;
	#else
	xp_mchar_t mpath[XP_PATH_MAX + 1];

	if (xp_wcstomcs_strict (path, mpath, xp_countof(mpath)) == -1) {
		return XP_NULL;
	}
	#endif
#endif

	if (dll == XP_NULL) {
		dll = (xp_dll_t*) xp_malloc (xp_sizeof(xp_dll_t));
		if (dll == XP_NULL) return XP_NULL;
		dll->__dynamic = xp_true;
	}
	else dll->__dynamic = xp_false;

#if defined(_WIN32)
	xp_assert (xp_sizeof(dll->handle) == xp_sizeof(HINSTANCE));
	handle = (void*)LoadLibraryEx (path, XP_NULL, 0);
#elif defined(__APPLE__) || defined(__MACOSX__)
	if (NSCreateObjectFileImageFromFile(
		mpath, &image) != NSObjectFileImageSuccess) {
		if (dll->__dynamic) xp_free (dll);
		return XP_NULL;
	}

	xp_assert (xp_sizeof(dll->handle) == xp_sizeof(NSModule));
	handle = (void*)NSLinkModule (image, mpath,
		NSLINKMODULE_OPTION_PRIVATE |
		NSLINKMODULE_OPTION_RETURN_ON_ERROR);
	NSDestroyObjectFileImage (image);
#else
	handle = dlopen (mpath, RTLD_NOW);
#endif

	if (handle == XP_NULL) {
		if (dll->__dynamic) xp_free (dll);	
		return XP_NULL;
	}

	dll->handle = handle;
	return dll;
}

int xp_dll_close (xp_dll_t* dll)
{
#if defined(_WIN32)
	if (FreeLibrary(dll->handle) != 0) return -1;
#elif defined(__APPLE__) || defined(__MACOSX__)
	NSUnLinkModule (dll->handle, NSUNLINKMODULE_OPTION_NONE);
#else
	if (dlclose(dll->handle) != 0) return -1;	
#endif
	if (dll->__dynamic) xp_free (dll);
	return 0;
}

void* xp_dll_lookup (xp_dll_t* dll, const xp_char_t* name)
{

#ifdef XP_CHAR_IS_MCHAR

	xp_assert (dll != XP_NULL);

	#if defined(_WIN32)
	return (void*)GetProcAddress (dll->handle, name);
	#elif defined(__APPLE__) || defined(__MACOSX__)
	return (void*)NSAddressOfSymbol(
		NSLookupSymbolInModule(dll->handle, name));
	#else
	return dlsym (dll->handle, name);
	#endif

#else

	void* x;
	xp_mchar_t* m;

	xp_assert (dll != XP_NULL);
	if ((m = xp_wcstomcs_dynamic (name)) == XP_NULL) return XP_NULL;

	#if defined(_WIN32)
	x = (void*)GetProcAddress (dll->handle, m);
	#elif defined(__APPLE__) || defined(__MACOSX__)
	x = (void*)NSAddressOfSymbol(
		NSLookupSymbolInModule(dll->handle, m));
	#else
	x = dlsym (dll->handle, m);
	#endif

	xp_free (m);
	return x;

#endif
}
